import datetime
import traceback

import wx
import os
from app import main_iic_process, UI
from app.CalWindow import CalWindow
from app.ReadWriteWindow import ReadWriteWindow
from app.main_iic_process import *
import app.utils as utils

FRAME_WIDTH = 1000
FRAME_HEIGHT = 1000
# 字体大小
FONT_SIZE = 14
READ_INTERVAL_MILLS = 1000
VERSION="v1.0.1_0205"
logMgr = utils.logMgr


class MainWindow(wx.Frame):
    def __init__(self, parent, title, app):
        wx.Frame.__init__(self, parent, title=title, size=(FRAME_WIDTH, FRAME_HEIGHT))
        self.app = app
        self.Bind(wx.EVT_CLOSE, self.onWindowClose)
        self.initView()
        self.initData()
        self.autoConnected()
        sys.__excepthook__=self.__handlerException

    def __handlerException(self, excType, excValue, tb):
        err_msg = ''.join(traceback.format_exception(excType, excValue, tb))
        try:
            logMgr.print(err_msg,level='e')
        except:
            pass
        sys.__excepthook__(excType, excValue, tb)

        dlg = wx.MessageDialog(None, err_msg, 'ERROR', wx.OK | wx.ICON_ERROR)
        dlg.ShowModal()
        dlg.Destroy()

    def initView(self):
        self.initMenuBar()
        self.initLayout()

    def initMenuBar(self):

        self.menubar = wx.MenuBar()

        menu1 = wx.Menu()
        versionItem = menu1.Append(-1, "版本号")
        introduceItem=menu1.Append(-1, "技术支持")
        self.Bind(wx.EVT_MENU, self.showVersion, versionItem)
        self.Bind(wx.EVT_MENU, self.showHelper, introduceItem)


        menu2 = wx.Menu()
        saveItem = menu2.AppendCheckItem(wx.ID_SAVE, "日志自动保存")
        # 默认自动保存
        saveItem.Check(True)

        self.menubar.Append(menu1, "帮助")
        self.menubar.Append(menu2, "设置")
        self.SetMenuBar(self.menubar)

        self.statusBar = wx.StatusBar(self, -1)  # 实例化 wx.StatusBar
        self.statusBar.SetFieldsCount(3)  # 状态栏分成3个区域
        self.statusBar.SetStatusWidths([-1, -1, -1])  # 区域宽度比列，用负数
        self.statusBar.SetStatusText("", 0)  # 给状态栏设文字
        self.SetStatusBar(self.statusBar)  # 将状态栏附加到框架上

    def initGridView(self):
        funsName = ["获取版本号", "获取版本日期", "红外原始数据ADC值", "NTC原始数据ADC值（或阻值）", "目标温度值，单位℃", "环境温度值，单位°C", "状态指示寄存器"]
        fgs = wx.FlexGridSizer(len(main_iic_process.funaddr), 2, 5, 5)
        self.btns = {}
        self.func_edittexts = {}
        index = 0
        for key in main_iic_process.funaddr.keys():
            regAddrBean = main_iic_process.funaddr.get(key)
            btn = wx.Button(self, -1, regAddrBean.name, name=key)
            self.btns[key] = btn
            btn.Bind(wx.EVT_BUTTON, self.onFuncButtonClick)
            fgs.Add(btn, 0, wx.ALIGN_RIGHT)
            tc = wx.TextCtrl(self)
            self.func_edittexts[key] = tc
            fgs.Add(tc, 0, wx.EXPAND)
            index += 1
        fgs.AddGrowableCol(1)

        return fgs

    def initLayout(self):
        rootLayout = wx.BoxSizer(wx.VERTICAL)
        self.root = rootLayout
        contentLayout = wx.BoxSizer(wx.VERTICAL)    # child 0
        btnLayout = wx.BoxSizer(wx.HORIZONTAL)
        optionLayout = wx.BoxSizer(wx.HORIZONTAL)    # child 1

        stateBox=wx.BoxSizer(wx.VERTICAL)
        scanStateBtn=wx.Button(self,-1,"拔插后手动扫描地址",size=(120,20))
        scanStateBtn.Bind(wx.EVT_BUTTON,self.scanDevAddr)

        self.stateText = wx.StaticText(self, -1, "未连接", size=(40, 20))
        self.stateText.SetForegroundColour((255, 0, 0))
        stateBox.Add(self.stateText,0)
        stateBox.Add(scanStateBtn,0,wx.TOP,border=0)

        self.timerBox = wx.CheckBox(self, -1, "定时读取")
        self.timerVal = wx.TextCtrl(self, -1, value=str(1000), size=(70, 20))
        optionLayout.Add(stateBox, 0, flag=wx.LEFT, border=20)
        optionLayout.Add(self.timerBox, 0, flag=wx.LEFT, border=40)
        optionLayout.Add(self.timerVal, 0, border=0)
        optionLayout.Add(wx.StaticText(self, -1, "ms", size=(40, 20)))
        self.timerBox.Bind(wx.EVT_CHECKBOX, self.onTimerBoxChange)
        self.timerVal.Bind(wx.EVT_TEXT, self.onTimerTextChange)

        btnStart = wx.Button(self, -1, "读取状态", pos=(0, 0), size=(100, 40))
        btnStart.Bind(wx.EVT_BUTTON, self.start)
        btnCancel = wx.Button(self, -1, "暂停", pos=(0, 0), size=(100, 40))
        btnCancel.Bind(wx.EVT_BUTTON, self.onCancel)
        btnCal = wx.Button(self, -1, "进入标定模式", pos=(0, 0), size=(100, 40))
        btnCal.SetBackgroundColour((0, 162, 232))
        btnCal.SetForegroundColour((255, 255, 255))
        btnCal.Bind(wx.EVT_BUTTON, self.onCal)

        btnLayout.Add(btnStart, 0)
        btnLayout.Add(btnCancel, 1, flag=wx.LEFT, border=50)
        btnLayout.Add(btnCal, 1, flag=wx.LEFT, border=50)

        attrNameArr = ["状态位", "ir_adc", "ntc_adc", "物温", "环温", "保留参数1", "保留参数2", "保留参数3"]
        self.textviewArr = []
        self.attrViewArr = []
        for i in range(0, 8):
            st = wx.StaticText(self, -1, attrNameArr[i], size=(120, 30), style=wx.ALIGN_CENTER)
            st.SetBackgroundColour((240, 240, 240))
            font = self.GetFont()
            font.SetPointSize(FONT_SIZE)
            st.SetFont(font)
            self.textviewArr.append(st)

            attr_st = wx.StaticText(self, -1, "-", size=(120, 30), style=wx.ALIGN_CENTER)
            attr_st.SetFont(font)
            attr_st.SetBackgroundColour((255, 255, 255))
            self.attrViewArr.append(attr_st)

        box1 = wx.BoxSizer(wx.HORIZONTAL)
        box2 = wx.BoxSizer(wx.HORIZONTAL)
        for i in range(0, 8):
            box1.Add(self.textviewArr[i], proportion=0, flag=wx.EXPAND, border=5)
            box2.Add(self.attrViewArr[i], proportion=0, flag=wx.EXPAND, border=5)

        contentLayout.Add(box1, 0, wx.EXPAND | wx.ALL, 5)
        contentLayout.Add(box2, 0, wx.EXPAND | wx.ALL, 5)
        optionLayout.Add(btnLayout, 0, wx.EXPAND | wx.TOP, border=-10)
        rootLayout.Add(contentLayout, 0, wx.EXPAND)
        rootLayout.Add(optionLayout, 0, wx.EXPAND | wx.TOP, border=20)
        # rootLayout.Add(btnLayout, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.TOP | wx.BOTTOM, border=30)
        rootLayout.Add(self.initGridView(), 0, wx.EXPAND | wx.TOP, 50)  # child 2

        self.cal_window=CalWindow(self)
        rootLayout.Add(self.cal_window, 0, wx.EXPAND | wx.TOP, 0)  # child 3
        self.cal_window.hide()

        rootLayout.Add(UI.Divider(self, (400, 1)), 0, wx.EXPAND | wx.TOP, 20)

        self.read_write_window = ReadWriteWindow(self)
        rootLayout.Add(self.read_write_window, 1, wx.EXPAND | wx.TOP, 20) # child 4
        self.SetSizer(rootLayout)
        self.SetBackgroundColour("#ffffff")
        # rootLayout.Fit(self)
    def scanDevAddr(self,e):
        self.master.dev_connected=False # 激活后台扫描线程
        self.master.iic_callback.onUSBClosed()

    def initData(self):
        pass

    def autoConnected(self):
        ver = 'I2C Data Process, v1.1, 20200119 by fatri_xm'
        # print(ver)
        callback = FatriIicCallback(self)
        # 初始化iic和usb连接
        self.master = iic_process(callback=callback)
        # 线程监控iic连接和初始化状态
        iic_dev_thread(self.master)

    def showVersion(self, e):
        wx.MessageBox("版本:"+VERSION)
    def showHelper(self, e):
        # wx.MessageBox('Text Entry Dialog', caption="使用说明" )
        pass

    def start(self, e):
        logMgr.print('start detect')

        # self.master.detect_data_once(self.master.regaddr.get('s_ir_data'), 9) //非子线程也可通信

        if self.timerBox.GetValue():
            # 键盘输入监听线程
            # self.master.input_monitor()
            self.master.start_nnew_th(self.master.detect_data_loop, (self.master.regaddr.get('s_ir_data'), 9))
        else:
            self.master.start_nnew_th(self.master.detect_data_once, (self.master.regaddr.get('s_ir_data'), 9))


    def onCancel(self, e):
        self.master.detect_data_stop()
    #
    # 进入标定模式
    #
    def onCal(self, e):
        # if not self.master.dev_connected:
        #     wx.MessageBox("设备未连接")
        #     return
        if self.master.calMode():
            self.root.Hide(0)
            self.root.Hide(1)
            self.root.Hide(2)
            self.cal_window.show()
            self.root.Layout()


    def notify(self, respData):
        # {'slave_addr': 0x2b, 's_work_mode': 0x00, 's_ir_data': 0x11,
        #  'version_addr':0x01,'version_date_addr':0x07,'ir_adc_addr':0x11,'ntc_adc_addr':0x13,'obj_temp_addr':0x15,
        #  'env_temp_addr':0x17,'state_indicator_addr':0x27}

        if respData.addr == self.master.regaddr.get("ir_adc_addr") and len(respData.srcDataArr) > 4:
            for i in range(0, len(respData.srcDataArr)):
                self.attrViewArr[i].SetLabel(str(respData.srcDataArr[i]))
        else:
            key = utils.findAddrKey(main_iic_process.funaddr, respData.addr)
            if key is not None:
                self.func_edittexts[key].SetValue(respData.extras)

        # 是否自动保存日志
        settingMenu = self.menubar.GetMenu(1)
        cb = settingMenu.FindItemById(wx.ID_SAVE)
        if cb.IsChecked():
            logMgr.print(str(respData.srcDataArr), cb.IsChecked())

    def onTimerTextChange(self, e):
        origin = self.master.read_interval_mills
        if self.master.running:
            wx.MessageBox("请先暂停读取")
            self.timerVal.SetValue(str(origin))
        try:
            val = int(self.timerVal.GetValue(), 10)
            global READ_INTERVAL_MILLS
            READ_INTERVAL_MILLS = val
            self.master.read_interval_mills = READ_INTERVAL_MILLS
        except ValueError:
            wx.MessageBox("请输入整数")
            self.timerVal.SetValue(str(origin))

    def onTimerBoxChange(self, e):
        cb = e.GetEventObject()
        if not cb.GetValue() and self.master.running:
            self.master.detect_data_stop()

    #
    # 寄存器查询
    #
    def onFuncButtonClick(self, e):
        obj = e.GetEventObject()
        name = obj.GetName()
        if utils.dictContains(main_iic_process.funaddr, name):
            regAddrBean = main_iic_process.funaddr.get(name)
            self.master.detect_data_once(regAddrBean.addr, regAddrBean.bytecnt,datalen=regAddrBean.datalen)
        elif name == "funBtn1":
            pass

    def onWindowClose(self, e):
        print("window closing...")
        main_iic_process.dev_monitor_enable = False  # 退出其余线程
        self.Destroy()



class FatriIicCallback(utils.IicCallback):
    def __init__(self, appWindow):
        self.appWindow = appWindow

    def onUSBConnectd(self):
        logMgr.print("onUSBConnectd")
        self.appWindow.stateText.SetForegroundColour(wx.Colour(0, 0, 255))
        self.appWindow.stateText.SetLabel("已连接")

    def onUSBClosed(self):
        self.appWindow.stateText.SetLabel("未连接")
        self.appWindow.stateText.SetForegroundColour(wx.Colour(255, 0, 0))
        logMgr.print("onUSBClosed")

    def onDevInit(self):
        self.appWindow.stateText.SetForegroundColour(wx.Colour(0, 0, 255))
        self.appWindow.stateText.SetLabel("已就绪:"+str(hex(self.appWindow.master.dev_addr)))

    def onReceived(self,respData):
        self.appWindow.notify(respData)

    def onStateOutput(self, level="i", msg="", errorCode=-1):
        if level == "e":
            logMgr.print(msg, level="e")
            self.appWindow.statusBar.SetStatusText(msg, 1)  # 状态栏错误信息
        else:
            logMgr.print(msg)
            self.appWindow.statusBar.SetStatusText(msg, 0)  # 状态栏信息


app = wx.App()
frame = MainWindow(None, "FATRI-Assistant", app)
frame.Show()
app.MainLoop()
